/* eslint-disable no-unneeded-ternary */
/* eslint-disable no-param-reassign */
/* eslint-disable no-unused-expressions */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-return-assign */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import {
  useUIStore,
  useNamespace,
  useClickOutside,
  useControlController,
} from '@ibiz-template/vue3-util';
import { createUUID } from 'qx-util';
import { ISearchBar } from '@ibiz/model-core';
import { h, computed, defineComponent, PropType, ref } from 'vue';
import { IControlProvider, IModal, IModalData } from '@ibiz-template/runtime';
import { OnClickOutsideResult } from '@ibiz-template/core';
import { OdooSearchBarController } from './odoo-search-bar.controller';
import {
  IGroupItem,
  CondopLabel,
  ISearchItem,
  IFilterItem,
  ICollectItem,
  SearchItemType,
} from './interfaces';
import { Modal } from './modal/modal';
import './odoo-search-bar.scss';

const CloseIcon = () => (
  <svg
    viewBox='0 0 1024 1024'
    version='1.1'
    xmlns='http://www.w3.org/2000/svg'
    p-id='4437'
    width='1em'
    height='1em'
  >
    <path
      d='M512 570.88l196.864 196.8 58.88-58.88L570.752 512l196.864-196.864-58.816-58.88L512 453.248 315.136 256.32l-58.88 58.88L453.248 512l-196.864 196.864 58.88 58.88z'
      fill='currentColor'
      p-id='4438'
    ></path>
  </svg>
);

export const OdooSearchBarControl = defineComponent({
  name: 'IBizOdooSearchBarControl',
  props: {
    /**
     * @description 搜索栏模型数据
     */
    modelData: {
      type: Object as PropType<ISearchBar>,
      required: true,
    },
    /**
     * @description 应用上下文对象
     */
    context: { type: Object as PropType<IContext>, required: true },
    /**
     * @description 视图参数对象
     * @default {}
     */
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    /**
     * @description 部件适配器
     */
    provider: { type: Object as PropType<IControlProvider> },
  },
  setup() {
    const c = useControlController(
      (...args) => new OdooSearchBarController(...args),
    );
    const ns = useNamespace(`control-odoo-search-bar`);
    const { zIndex } = useUIStore();

    /**
     * 搜索列表
     */
    const searchList: ISearchItem[] = [
      {
        type: 'filter',
        caption: '筛选',
        icon: { appId: '', cssClass: 'fa fa-filter' },
      },
      {
        type: 'group',
        caption: '分组方式',
        icon: { appId: '', cssClass: 'layers-outline' },
      },
      {
        type: 'collect',
        caption: '收藏夹',
        icon: { appId: '', cssClass: 'fa fa-star' },
      },
    ];

    /**
     * popper样式
     */
    const popperStyle = { zIndex: zIndex.increment() };

    /**
     * 下拉显示状态
     */
    const dropDownVisible = ref<boolean>(false);

    /**
     * 下拉框Ref
     */
    const dropDownRef = ref<HTMLDivElement>();

    /**
     * 快速搜索
     */
    const quickSearch = ref<string>('');

    /**
     * 搜索栏Ref
     */
    const searchRef = ref<HTMLDivElement>();

    /**
     * 是否聚焦
     */
    const isFocus = ref<boolean>(false);

    /**
     * 显示收藏保存
     */
    const showCollectSave = ref<boolean>(false);

    let funcs: OnClickOutsideResult | undefined;

    /**
     * 数据集
     */
    const items = computed(() => {
      const { filter, collect, group } = c.state;
      return {
        group,
        filter,
        collect,
      };
    });

    /**
     * 可选分组
     */
    const optionalGroup = computed(() => {
      return c.state.schemaFields.filter(
        s =>
          items.value.group?.findIndex(
            g => g.appDEFieldId.toLowerCase() === s.key,
          ) === -1 && s.description.includes(quickSearch.value),
      );
    });

    /**
     * 显示选中数据
     */
    const selections = computed(() => {
      const { selectedFilter, condop, selectedCollect, selectedGroup } =
        c.state;
      const result: ISearchItem[] = [];

      // 如果没有选择任何项，直接返回空数组
      if (!selectedFilter.length && !selectedGroup.length && !selectedCollect)
        return result;

      // 处理筛选条件
      if (selectedFilter.length && c.state.showFilter) {
        const filters: IFilterItem[] = [];
        const exclusiveFilters: Record<string, IFilterItem[]> = {};
        const orGroupFilters: Record<string, IFilterItem[]> = {};

        selectedFilter.forEach(item => {
          const ORGroup = Object.keys(c.filterORgroup).find(orKey =>
            c.filterORgroup[orKey].includes(item.id),
          );
          const Exclusive = Object.keys(c.exclusive).find(exGroup =>
            c.exclusive[exGroup]?.includes(item.id),
          );
          if (ORGroup) {
            const group = orGroupFilters[ORGroup] || [];
            group.push(item);
            orGroupFilters[ORGroup] = group;
          } else if (Exclusive) {
            const group = exclusiveFilters[Exclusive] || [];
            group.push(item);
            exclusiveFilters[Exclusive] = group;
          } else {
            filters.push(item);
          }
        });

        if (filters.length)
          result.push({
            type: 'filter',
            icon: { appId: '', cssClass: 'fa fa-filter' },
            filterType: 'FILTER',
            caption: filters
              .map(s => s.caption)
              .join(` ${CondopLabel[condop]} `),
          });

        if (Object.keys(orGroupFilters).length)
          Object.keys(orGroupFilters).forEach(orId => {
            result.push({
              type: 'filter',
              filterTypeId: orId,
              icon: { appId: '', cssClass: 'fa fa-filter' },
              filterType: 'OR',
              caption: orGroupFilters[orId]
                .map(s => s.caption)
                .join(` ${CondopLabel.OR} `),
            });
          });

        if (Object.keys(exclusiveFilters).length)
          Object.keys(exclusiveFilters).forEach(exId => {
            result.push({
              type: 'filter',
              filterTypeId: exId,
              icon: { appId: '', cssClass: 'fa fa-filter' },
              filterType: 'EXCLUSIVE',
              caption: exclusiveFilters[exId].map(s => s.caption).join(''),
            });
          });
      }

      // 处理分组条件
      if (selectedGroup.length && c.state.showGroup)
        result.push({
          type: 'group',
          icon: { appId: '', cssClass: 'layers-outline' },
          caption: selectedGroup
            .map(g => {
              if (g.dateFormat?.length) {
                return c.dateFormat
                  .filter(d => g.dateFormat!.includes(d.value))
                  .map(d => `${g.caption}: ${d.label}`)
                  .join(' > ');
              }
              return g.caption;
            })
            .join(' > '),
        });

      // 处理收藏条件
      if (selectedCollect && c.state.showCollect)
        result.push({
          type: 'collect',
          icon: { appId: '', cssClass: 'fa fa-star' },
          caption: selectedCollect.caption,
        });
      return result;
    });

    /**
     * @description 是否选中
     * @param {*} item
     * @returns {*}  {boolean}
     */
    const isSelected = (item: any): boolean => {
      const { selectedGroup, selectedFilter, selectedCollect } = c.state;
      const selected: IData[] = [...selectedGroup, ...selectedFilter];
      if (selectedCollect) selected.push(selectedCollect);
      return (
        !!selected.find(s => s.id === item.id) || item.dateFormat?.length > 0
      );
    };

    /**
     * @description 气泡关闭
     */
    const onPopoverHide = () => {
      funcs?.pause();
      showCollectSave.value = false;
    };

    /**
     * @description 打开气泡
     * @returns {*}
     */
    const onPopoverShow = () => {
      if (funcs) return funcs.proceed();
      funcs = useClickOutside(dropDownRef as any, event => {
        if (!(event.target as HTMLElement).closest(`.${ns.e('reference')}`))
          dropDownVisible.value = false;
      });
    };

    /**
     * @description 开始搜索
     * @param {MouseEvent} event
     */
    const onSearchClick = (event: MouseEvent) => {
      event.stopPropagation();
      c.onSearch();
    };

    /**
     * @description 保存收藏
     * @returns {*}
     */
    const saveCollect = async () => {
      const { selectedFilter, selectedGroup, collectName } = c.state;
      if (!collectName) return ibiz.message.error('必须输入收藏名称');
      const item: ICollectItem = {
        id: createUUID(),
        isCustom: true,
        filterIds: selectedFilter.map(f => f.id),
        groups: selectedGroup,
        caption: collectName,
      };
      showCollectSave.value = false;
      await c.updateByType('collect', 'update', item);
      c.state.collectName = c.view.model.caption!;
    };

    /**
     * @description 处理下拉显示改变
     * @param {boolean} val
     */
    const handleVisibleChange = (val: boolean): void => {
      val ? funcs?.pause() : funcs?.proceed();
      // 关闭时重置值
      if (!val) quickSearch.value = '';
    };

    /**
     * @description 打开模态
     * @param {IFilterItem} [item]
     */
    const onOpenModal = async (item?: IFilterItem) => {
      const overlay = ibiz.overlay.createModal(
        (modal: IModal) => {
          return h(Modal, {
            item,
            modal,
            controller: c,
          });
        },
        {},
        {
          width: '800px',
          height: 'auto',
        } as any,
      );
      funcs?.pause();
      overlay.present();
      const result: IModalData = await overlay.onWillDismiss();
      funcs?.proceed();
      if (result.ok && result.data)
        c.updateByType('filter', 'update', result.data[0] as IFilterItem);
    };

    /**
     * @description 处理删除
     * @param {SearchItemType} type
     * @param {(IGroupItem | IFilterItem | ICollectItem)} item
     */
    const handleRemove = async (
      type: SearchItemType,
      item: IGroupItem | IFilterItem | ICollectItem,
    ): Promise<void> => {
      funcs?.pause();
      const result = await ibiz.confirm.warning({
        title: '警告',
        desc: `您确定要删除 ${item.caption} 吗？删除后不可恢复！`,
      });
      funcs?.proceed();
      if (result) c.updateByType(type, 'remove', item);
    };

    /**
     * @description 添加自定义分组
     * @param {string} key
     */
    const addCustomGroup = async (key: string): Promise<void> => {
      const field = c.state.schemaFields.find(s => s.key === key);
      if (field) {
        const item: IGroupItem = {
          isCustom: true,
          id: createUUID(),
          appDEFieldId: key,
          type: field.type,
          isExpand: false,
          caption: field.description,
          appCodeListId: field.enumSource,
        };
        await c.updateByType('group', 'update', item);
      }
    };

    /**
     * @description 处理列表项点击
     * @param {SearchItemType} type
     * @param {(IGroupItem | IFilterItem | ICollectItem)} item
     * @returns {*}
     */
    const handleListItemClick = (
      type: SearchItemType,
      item: IGroupItem | IFilterItem | ICollectItem,
    ) => {
      if (type === 'group' && (item as IGroupItem).type === 'date') {
        (item as IGroupItem).isExpand = !(item as IGroupItem).isExpand;
        return;
      }
      c.onSearchItemClick(type, item);
    };

    /**
     * @description 设置日期分组格式
     * @param {IGroupItem} item
     * @param {string} val
     */
    const setDateFormat = (item: IGroupItem, val: string) => {
      if (!item.dateFormat) item.dateFormat = [];
      const index = item.dateFormat.findIndex(d => d === val);
      index !== -1
        ? item.dateFormat.splice(index, 1)
        : item.dateFormat.push(val);
      const selected = item.dateFormat.length > 0 ? true : false;
      const selectIndex = c.state.selectedGroup.findIndex(
        s => s.id === item.id,
      );
      if (selectIndex !== -1 && !selected) {
        c.state.selectedGroup.splice(selectIndex, 1);
      } else if (selectIndex === -1 && selected) {
        c.state.selectedGroup.push(item);
      }
      c.execGroup();
    };

    /**
     * @description 触发源点击
     * @param {MouseEvent} event
     */
    const onReferenceClick = (event: MouseEvent) => {
      if (
        (event.target as HTMLElement).closest(
          `.${ns.em('reference', 'suffix')}`,
        )
      ) {
        dropDownVisible.value = !dropDownVisible.value;
      } else {
        dropDownVisible.value = true;
      }
    };

    /**
     * @description 绘制搜索项
     * @param {ISearchItem} item
     * @returns {*}
     */
    const renderSearchItem = (item: ISearchItem) => {
      return (
        <div class={[ns.e('search-item'), ns.em('search-item', item.type)]}>
          <div class={ns.em('search-item', 'icon')}>
            <iBizIcon icon={item.icon}></iBizIcon>
          </div>
          <div class={ns.em('search-item', 'caption')} title={item.caption}>
            {item.caption}
          </div>
          <div
            class={ns.em('search-item', 'remove')}
            onClick={() => c.onClearSelectedByType(item)}
          >
            {CloseIcon()}
          </div>
        </div>
      );
    };

    /**
     * @description 绘制默认呈现内容
     * @returns {*}
     */
    const renderDefault = () => {
      return (
        <div
          ref={searchRef}
          class={[ns.e('reference'), ns.is('search-focus', isFocus.value)]}
          onClick={onReferenceClick}
        >
          <div class={ns.em('reference', 'left')}>
            <el-button
              class={ns.em('reference', 'prefix')}
              type='text'
              onClick={(event: MouseEvent) => onSearchClick(event)}
            >
              <iBizIcon icon={{ cssClass: 'fa fa-search' }} />
            </el-button>
            <div class={ns.em('reference', 'content')}>
              <div class={ns.e('search-content')}>
                {selections.value.map(item => {
                  return renderSearchItem(item);
                })}
                <el-input
                  type='text'
                  placeholder='搜索...'
                  v-model={c.state.query}
                  onFocus={() => (isFocus.value = true)}
                  onBlur={() => (isFocus.value = false)}
                  onChange={() => c.onSearch()}
                />
              </div>
            </div>
          </div>
          <el-button
            class={[
              ns.em('reference', 'suffix'),
              ns.is('active', dropDownVisible.value),
            ]}
          >
            <ion-icon
              name={
                dropDownVisible.value
                  ? 'chevron-up-outline'
                  : 'chevron-down-outline'
              }
            ></ion-icon>
          </el-button>
        </div>
      );
    };

    /**
     * @description 绘制列表行为
     * @param {SearchItemType} type
     * @returns {*}
     */
    const renderListAction = (type: SearchItemType) => {
      if (type === 'filter')
        return (
          <div class={ns.em('list', 'item')} onClick={() => onOpenModal()}>
            <div title='添加自定义筛选' class='caption action-caption'>
              添加自定义筛选
            </div>
          </div>
        );
      if (type === 'collect')
        return [
          <div class={ns.em('list', 'item')}>
            <div
              title='保存当前搜索'
              class='caption action-caption'
              onClick={() => {
                showCollectSave.value = !showCollectSave.value;
              }}
            >
              保存当前搜索
            </div>
            <div class={['action', 'collapse-icon']}>
              <ion-icon
                name={
                  showCollectSave.value
                    ? 'chevron-up-outline'
                    : 'chevron-down-outline'
                }
              ></ion-icon>
            </div>
          </div>,
          showCollectSave.value && (
            <div class={ns.e('expand-item')}>
              <div class={ns.em('expand-item', 'form')}>
                <el-input
                  v-model={c.state.collectName}
                  class={ns.em('expand-item', 'caption')}
                  placeholder='请输入收藏名称'
                ></el-input>
                <div class={ns.em('expand-item', 'btn')}>
                  <el-button onClick={() => saveCollect()}>保存</el-button>
                </div>
              </div>
            </div>
          ),
        ];
      return (
        <el-dropdown
          trigger='click'
          class={ns.e('dropdown')}
          onCommand={addCustomGroup}
          onVisibleChange={handleVisibleChange}
          popper-class={ns.em('dropdown', 'popper')}
        >
          {{
            default: () => {
              return (
                <div class={ns.em('list', 'item')}>
                  <div title='添加自定义分组' class='caption action-caption'>
                    添加自定义分组
                  </div>
                  <div class={['action', 'collapse-icon']}>
                    <ion-icon name='chevron-down-outline'></ion-icon>
                  </div>
                </div>
              );
            },
            dropdown: () => {
              return (
                <div class={ns.em('dropdown', 'popper-content')}>
                  <el-input v-model={quickSearch.value}></el-input>
                  <el-dropdown-menu>
                    {optionalGroup.value.map(item => {
                      return (
                        <el-dropdown-item command={item.key}>
                          {item.description}
                        </el-dropdown-item>
                      );
                    })}
                  </el-dropdown-menu>
                </div>
              );
            },
          }}
        </el-dropdown>
      );
    };

    /**
     * @description 绘制列表项行为
     * @param {SearchItemType} type
     * @param {*} item
     * @returns {*}
     */
    const renderListItemAction = (type: SearchItemType, item: any) => {
      const result = [];
      if (type === 'filter')
        result.push(
          <iBizIcon
            title='设置'
            class='action-icon setting-icon'
            icon={{ cssClass: 'fa fa-fw fa-cog' }}
            onClick={() => onOpenModal(item as IFilterItem)}
          />,
        );
      if (item.type === 'date')
        result.push(
          <div class={['action', 'collapse-icon']}>
            <ion-icon
              name={
                item.isExpand ? 'chevron-up-outline' : 'chevron-down-outline'
              }
            ></ion-icon>
          </div>,
        );
      if (item.isCustom)
        result.push(
          <iBizIcon
            title='删除'
            class='action-icon remove-icon'
            icon={{ cssClass: 'close-outline' }}
            onClick={() => handleRemove(type, item)}
          />,
        );
      return result;
    };

    /**
     * @description 绘制列表展开项
     * @param {SearchItemType} type
     * @param {*} item
     */
    const renderListExpandItem = (type: SearchItemType, item: any) => {
      if (!item.isExpand) return null;
      if ((item as IGroupItem).type === 'date')
        return (
          <div class={ns.e('expand-item')}>
            <div class={ns.em('expand-item', 'list')}>
              {c.dateFormat.map(d => {
                return (
                  <div
                    class={[
                      'item',
                      ns.is('selected', item.dateFormat?.includes(d.value)),
                    ]}
                    onClick={() => setDateFormat(item, d.value)}
                  >
                    {d.label}
                  </div>
                );
              })}
            </div>
          </div>
        );
      return null;
    };

    /**
     * @description 绘制列表项
     * @param {SearchItemType} type
     * @param {(IFilterItem | ICollectItem | IGroupItem)} item
     * @returns {*}
     */
    const renderListItem = (
      type: SearchItemType,
      item: IFilterItem | ICollectItem | IGroupItem,
    ) => {
      return [
        <div
          class={ns.em('list', 'item')}
          onClick={() => handleListItemClick(type, item)}
        >
          <iBizIcon
            icon={{ cssClass: 'fa fa-check' }}
            class={['selected-icon', ns.is('selected', isSelected(item))]}
          ></iBizIcon>
          <div title={item.caption} class='caption'>
            {item.caption}
          </div>
          <div
            class='action'
            onClick={(evt: MouseEvent) => evt.stopPropagation()}
          >
            {renderListItemAction(type, item)}
          </div>
        </div>,
        renderListExpandItem(type, item),
      ];
    };

    /**
     * 绘制列表
     *
     * @param {SearchItemType} type
     * @return {*}
     */
    const renderList = (type: SearchItemType) => {
      const list = searchList.find(l => l.type === type);
      if (!list) return;
      return (
        <div class={[ns.e('list'), ns.e(`${type}-list`)]}>
          <div class={ns.em('list', 'header')}>
            <iBizIcon icon={list.icon} class='icon'></iBizIcon>
            <div class='caption'>
              <span title={list.caption}>{list.caption}</span>
            </div>
          </div>
          <div class={ns.em('list', 'content')}>
            {items.value[type]?.map(item => {
              return [
                renderListItem(type, item),
                (item as IData).showSeparator && (
                  <el-divider
                    class={ns.em('list', 'separator')}
                    border-style='double'
                  />
                ),
              ];
            })}
          </div>
          <div class={ns.em('list', 'footer')}>{renderListAction(type)}</div>
        </div>
      );
    };

    return {
      c,
      ns,
      popperStyle,
      dropDownRef,
      dropDownVisible,
      renderList,
      renderDefault,
      onPopoverHide,
      onPopoverShow,
    };
  },
  render() {
    return (
      <iBizControlBase controller={this.c} class={[this.ns.b()]}>
        <el-popover
          width='600'
          trigger='click'
          visible={this.dropDownVisible}
          onHide={this.onPopoverHide}
          onShow={this.onPopoverShow}
          popper-style={this.popperStyle}
          popper-class={this.ns.e('popover')}
        >
          {{
            reference: () => this.renderDefault(),
            default: () => {
              return (
                <div ref='dropDownRef' class={this.ns.e('content')}>
                  {this.c.state.showFilter && this.renderList('filter')}
                  {this.c.state.showGroup && this.renderList('group')}
                  {this.c.state.showCollect && this.renderList('collect')}
                </div>
              );
            },
          }}
        </el-popover>
      </iBizControlBase>
    );
  },
});
